package com.yonyou.pmclouds.team.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.entity.PageObject;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.ChineseStringUtils;
import com.yonyou.pmclouds.basecom.util.CommonProgramConsts;
import com.yonyou.pmclouds.basecom.util.DistanceUtils;
import com.yonyou.pmclouds.basecom.util.SqlUtil;
import com.yonyou.pmclouds.businessobject.util.BulkDataSplitUtils;
import com.yonyou.pmclouds.comprehensiveacceptance.rmiitf.ComprehensiveAcceptanceQuery;
import com.yonyou.pmclouds.offline.aspect.Offline;
import com.yonyou.pmclouds.offline.entity.OffLineDataKeyConst;
import com.yonyou.pmclouds.offline.entity.OffLineInvocationContext;
import com.yonyou.pmclouds.offline.rmiitf.IOffLineDataQueryService;
import com.yonyou.pmclouds.organization.entity.OrgAndRoleVO;
import com.yonyou.pmclouds.organization.entity.OrganizationVO;
import com.yonyou.pmclouds.organization.mapper.OrgAndRoleMapper;
import com.yonyou.pmclouds.organization.mapper.OrganizationMapper;
import com.yonyou.pmclouds.organization.rmiitf.OrganizationQuery;
import com.yonyou.pmclouds.outter.user.UserInfoServerQuery;
import com.yonyou.pmclouds.plan.rmiitf.ProjectPlanQuery;
import com.yonyou.pmclouds.problemlog.entity.ProblemLogVO;
import com.yonyou.pmclouds.problemlog.mapper.ProblemLogMapper;
import com.yonyou.pmclouds.problemlog.service.rmiitf.ProblemLogQuery;
import com.yonyou.pmclouds.procedure.entity.ProcedureRefVO;
import com.yonyou.pmclouds.procedure.rmiitf.ProcedureQuery;
import com.yonyou.pmclouds.project.entity.*;
import com.yonyou.pmclouds.project.mapper.ProjectMapper;
import com.yonyou.pmclouds.project.rmiimpl.ProjectSimpleQueryImpl;
import com.yonyou.pmclouds.projectstatus.rmiitf.ProjectStatusQuery;
import com.yonyou.pmclouds.projecttype.rmiitf.ProjectTypeQuery;
import com.yonyou.pmclouds.team.entity.TeamEnterpriseRefVO;
import com.yonyou.pmclouds.team.entity.TeamMemberVO;
import com.yonyou.pmclouds.team.mapper.TeamMapper;
import com.yonyou.pmclouds.team.rmiitf.ProjectRefWithTeamQuery;
import com.yonyou.pmclouds.team.rmiitf.TeamEnterpriseQuery;
import com.yonyou.pmclouds.team.rmiitf.TeamMemberQuery;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = ProjectRefWithTeamQuery.class)
@Offline(dataFrom = OffLineDataKeyConst.DATA_FROM_PROJECT)
public class ProjectRefWithTeamQueryImpl implements ProjectRefWithTeamQuery, IOffLineDataQueryService {
    @Autowired
    private ProjectSimpleQueryImpl projectQuery;
    @Autowired
    private ProblemLogQuery problemQuery;
    @Autowired
    private TeamMapper mapper;
    @Autowired
    private ProjectTypeQuery projectTypeQuery;
    @Autowired
    private ProjectStatusQuery projectStatusQuery;

    @Autowired
    private OrgAndRoleMapper roleMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private OrganizationQuery organizationQuery;
    @Autowired
    private ProblemLogMapper problemLogMapper;
    @Autowired
    private ProjectPlanQuery projectPlanQuery;
    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private ProcedureQuery procedureQuery;

    @Autowired
    private TeamEnterpriseQuery teamEnterpriseQuery;
    @Autowired
    private TeamMemberQuery teamMemberQuery;

    @Autowired
    private ComprehensiveAcceptanceQuery acceptanceQuery;

    @Autowired
    private UserInfoServerQuery userInfoServerQuery;

    @Override
    public PageObject<ProjectRefVO> queryOfUser(String userId, String tenantid, Byte[] state, int start, int offset, String[] pkRoles) throws BusinessException {

        if (offset > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
            offset = CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE;
        }

        ProjectRefVO[] projectRefVOs = this.queryPermProByUser(userId, tenantid, state, start, offset, pkRoles);

        int count = projectRefVOs == null ? 0 : projectRefVOs.length;
        return new PageObject<>(projectRefVOs, count, start);
    }

    @Override
    public PageObject<ProjectWithProblemVO> queryOfUserProblem(String userId, String tenantid, Byte state, int start, int offset, String[] pkRoles, String[] filterOrgs) throws BusinessException {
        if (offset > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
            offset = CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE;
        }

        ProjectWithProblemVO[] finalRetVOs = queryOfUserAndRole(userId, tenantid, state, start, offset, pkRoles, filterOrgs);
        int count = finalRetVOs.length;

        if (ArrayUtils.isEmpty(finalRetVOs)) {
            return new PageObject<>(new ProjectWithProblemVO[0], count, start);
        }

        //  这里做分页，减小问题和计划的查询
        finalRetVOs = ArrayUtils.subarray(finalRetVOs, start, start + offset);

        return new PageObject<>(finalRetVOs, count, start);
    }

    private ProjectWithProblemVO[] queryOfUserAndRole(String userId, String tenantid, Byte state, int start, int offset,
                                                      String[] pkRoles, String[] filterOrgs) throws BusinessException {
        // 处理人员参与的项目
        ProjectVO[] joinProjects = queryProByTeamAndOrg(userId, tenantid, state, filterOrgs);
        // 处理角色下的项目
        ProjectVO[] orgProjects = queryProByOrg(pkRoles, tenantid, state, start, offset, filterOrgs);
        // 组装vo
        ProjectWithProblemVO[] projectWithProblemVOS = genPrjWithProblemVOs(tenantid, joinProjects, orgProjects);

        setPrjBuziInfo(projectWithProblemVOS);

        return projectWithProblemVOS;
    }

    @Override
    public ProjectWithProblemVO[] queryOfCondition(ProjectSearchConditionVO searchConditionVO) throws BusinessException {
        String tenantId = RuntimeEnvironment.getTenantId();
        String userId = RuntimeEnvironment.getLoginUserId();
        String[] pkRoles = searchConditionVO.getPkRoles();
        int pageStart = searchConditionVO.getPageStart();
        int pageSize = searchConditionVO.getPageSize() == 0 ? 1000 : searchConditionVO.getPageSize();

        ProjectWithProblemVO[] finalRetVOs = queryOfUserAndRole(userId, tenantId, null, pageStart, pageSize, pkRoles, null);

        if (ArrayUtils.isEmpty(finalRetVOs)) {
            return new ProjectWithProblemVO[0];
        }

        return finalRetVOs;
    }

    private void setPrjBuziInfo(ProjectWithProblemVO[] finalRetVOs) throws BusinessException {
        Set<String> finalProjectIds = new HashSet<>(finalRetVOs.length);

        Map<String, String> pkProjectTypeMap = new HashMap<String, String>();
        Map<String, String> pkProjectStatusMap = new HashMap<String, String>();

        for (ProjectWithProblemVO finalRetVO : finalRetVOs) {
            finalProjectIds.add(finalRetVO.getPkProject());
            pkProjectTypeMap.put(finalRetVO.getPkProject(), finalRetVO.getPkProjectType());
            pkProjectStatusMap.put(finalRetVO.getPkProject(), finalRetVO.getPkProjectStatus());
        }
//      统计项目的，待整改，待验收，已关闭问题数量
        Map<String, Integer[]> problemCountMap = getProblemStateNum(finalProjectIds.toArray(new String[0]));
//      统计项目的，总进度
        Map<String, Integer> projectProgressMap = projectPlanQuery.getTotalProgress(finalProjectIds.toArray(new String[0]));

        Map<String, String> typeMap = null;
        Map<String, String> statusMap = null;
        if (pkProjectTypeMap.size() > 0) {
            typeMap = projectTypeQuery.queryNamesByIds(new HashSet<>(pkProjectTypeMap.values()).toArray(new String[0]));
        }
        if (pkProjectStatusMap.size() > 0) {
            statusMap = projectStatusQuery.queryNamesByIds(new HashSet<>(pkProjectStatusMap.values()).toArray(new String[0]));
        }

        for (ProjectWithProblemVO finalRetVO : finalRetVOs) {
            // 不同问题类型数量：待整改，待验收，已关闭
            Integer[] problemCount = problemCountMap.get(finalRetVO.getPkProject());
            if (problemCount != null) {
                finalRetVO.setRepairingNum(problemCount[0] == null ? 0 : problemCount[0]); //待整改
                finalRetVO.setAcceptingNum(problemCount[1] == null ? 0 : problemCount[1]); //待验收
                finalRetVO.setEndNum(problemCount[2] == null ? 0 : problemCount[2]);       //已关闭
            } else {
                finalRetVO.setRepairingNum(0); //待整改
                finalRetVO.setAcceptingNum(0); //待验收
                finalRetVO.setEndNum(0);       //已关闭
            }
            // 总进度
            if (projectProgressMap.get(finalRetVO.getPkProject()) == null) {
                finalRetVO.setTotalProgress(0);    //总进度
            } else {
                finalRetVO.setTotalProgress(projectProgressMap.get(finalRetVO.getPkProject()));    //总进度
            }
        }
        if (typeMap != null && statusMap != null) {
            addTypeAndStatusNames(finalRetVOs, typeMap, statusMap, pkProjectTypeMap, pkProjectStatusMap);
        }
    }

    private ProjectWithProblemVO[] genPrjWithProblemVOs(String pkTenant, ProjectVO[] joinProjects, ProjectVO[] orgProjects) throws BusinessException {

        Set<String> orgSet = new HashSet<>();
        for (ProjectVO joinProject : joinProjects) {
            if (StringUtils.isNotEmpty(joinProject.getPkOrg())) {
                orgSet.add(joinProject.getPkOrg());
            }
        }
        for (ProjectVO orgProject : orgProjects) {
            if (StringUtils.isNotEmpty(orgProject.getPkOrg())) {
                orgSet.add(orgProject.getPkOrg());
            }
        }

        Map<String, OrganizationVO> prjOrgMap = getOrg(pkTenant, orgSet.toArray(new String[0]));

        Map<String, ProjectWithProblemVO> projectWithProblemVOMap = new HashMap<String, ProjectWithProblemVO>();

        ProjectWithProblemVO[] joinRetProjects = new ProjectWithProblemVO[joinProjects.length];
        for (int i = 0; i < joinRetProjects.length; i++) {
            ProjectWithProblemVO vo = transProjectToWithProblem(joinProjects[i]);
            vo.setIsJoinIn(true);
            vo.setOrgCode(prjOrgMap.get(vo.getPkOrg()) == null ? "" : prjOrgMap.get(vo.getPkOrg()).getScode());
            vo.setOrgName(prjOrgMap.get(vo.getPkOrg()) == null ? "" : prjOrgMap.get(vo.getPkOrg()).getSname());
            projectWithProblemVOMap.put(vo.getPkProject(), vo);
            joinRetProjects[i] = vo;
        }

        List<ProjectWithProblemVO> orgRetList = new ArrayList<ProjectWithProblemVO>();

        for (int i = 0; i < orgProjects.length; i++) {
            ProjectWithProblemVO vo = transProjectToWithProblem(orgProjects[i]);

            if (!projectWithProblemVOMap.containsKey(vo.getPkProject())) {
                vo.setIsJoinIn(false);
                vo.setOrgCode(prjOrgMap.get(vo.getPkOrg()) == null ? "" : prjOrgMap.get(vo.getPkOrg()).getScode());
                vo.setOrgName(prjOrgMap.get(vo.getPkOrg()) == null ? "" : prjOrgMap.get(vo.getPkOrg()).getSname());
                orgRetList.add(vo);
            }
        }
        ProjectWithProblemVO[] orgRetProjects = orgRetList.toArray(new ProjectWithProblemVO[0]);
        // 排序
        sortProjectProblems(joinRetProjects);
        sortProjectProblems(orgRetProjects);

        ProjectWithProblemVO[] finalRetVOs = ArrayUtils.addAll(joinRetProjects, orgRetProjects);

        return finalRetVOs;
    }

    private ProjectWithProblemVO transProjectToWithProblem(ProjectVO projectVO) {
        ProjectWithProblemVO vo = new ProjectWithProblemVO();

        vo.setPkProject(projectVO.getPkProject());
        vo.setManager(projectVO.getManager());
        vo.setPkTenant(projectVO.getPkTenant());
        vo.setScode(projectVO.getScode());
        vo.setSname(projectVO.getSname());
        vo.setState(projectVO.getProjectState());
        vo.setPkOrg(projectVO.getPkOrg());
        vo.setPkProjectType(projectVO.getPkProjectType());
        vo.setPkProjectStatus(projectVO.getPkProjectStatus());
        //是否重点项目
        vo.setIskey(projectVO.getIskey());
        return vo;
    }

    private void sortProjectProblems(ProjectWithProblemVO[] retProjects) {
        Arrays.sort(retProjects, new Comparator<ProjectWithProblemVO>() {
            @Override
            public int compare(ProjectWithProblemVO o1, ProjectWithProblemVO o2) {
                if (o1 == o2) {
                    return 0;
                }
                if (o1 == null) {
                    return 1;
                }
                if (o2 == null) {
                    return -1;
                }
                if (o1.getIskey().compareTo(o2.getIskey()) != 0) {
                    return -o1.getIskey().compareTo(o2.getIskey());
                }
                int i = ChineseStringUtils.compareInDict(o1.getOrgCode(), o2.getOrgCode());
                if (i != 0) {
                    return i;
                }
                return ChineseStringUtils.compareInDict(o1.getScode(), o2.getScode());
            }
        });
    }

    /**
     * 统计项目的，待整改，待验收，已关闭问题数量
     */
    private Map<String, Integer[]> getProblemStateNum(String[] pkProjects) {

        if (ArrayUtils.isEmpty(pkProjects))
            return new HashMap<String, Integer[]>();
        // TODO 这部分效率可能存在极大问题
        // TODO 直接用group by统计吧
        ProblemLogVO[] problemLogVOS = problemLogMapper.getByPkProjects(SqlUtil.getSqlIn(pkProjects));
        Map<String, Integer[]> problemCountMap = new HashMap<>(); //0-待整改，1-待验收，2-已关闭
        if (ArrayUtils.isNotEmpty(problemLogVOS)) {
            for (ProblemLogVO vo : problemLogVOS) {
                if (vo == null || vo.getPk_project() == null) continue;
                if (problemCountMap.get(vo.getPk_project()) == null) {
                    problemCountMap.put(vo.getPk_project(), new Integer[3]);
                }
                if (problemCountMap.get(vo.getPk_project())[vo.getBillstatus()] == null) {
                    problemCountMap.get(vo.getPk_project())[vo.getBillstatus()] = 0;
                }
                problemCountMap.get(vo.getPk_project())[vo.getBillstatus()]++;
            }
        }
        return problemCountMap;
    }

    /**
     * 为每个ProjectWithProblemVO设置projectTypeName, projectStatusName
     *
     * @param result
     * @param typeMap
     * @param statusMap
     */
    private void addTypeAndStatusNames(ProjectWithProblemVO[] result, Map<String, String> typeMap, Map<String, String> statusMap,
                                       Map<String, String> pkProjectTypeMap, Map<String, String> pkProjectStatusMap) {
        String projectId = null;
        String projectTypeId = null;
        String projectStatusId = null;
        for (ProjectWithProblemVO vo : result) {
            projectId = vo.getPkProject();
            projectTypeId = pkProjectTypeMap.get(projectId);
            projectStatusId = pkProjectStatusMap.get(projectId);
            if (!StringUtils.isEmpty(projectTypeId)) {
                vo.setProjectTypeName(typeMap.get(projectTypeId));
            }
            if (!StringUtils.isEmpty(projectStatusId)) {
                vo.setProjectStatusName(statusMap.get(projectStatusId));
            }
        }
    }

    @Override
    public int checkProjectStatus(String userId, String tenantid, String projectid) throws BusinessException {
        Integer[] states = mapper.isPersonInProject(userId, tenantid, projectid);
        if (ArrayUtils.isEmpty(states)) {
            return PROJECT_NOT_EXIST;
        }
        if (states[0] != ProjectConst.STATE_GOING) {
            return PROJECT_END;
        }
        ProjectVO proj = projectQuery.queryProject(projectid);
        if (proj == null) {
            return PROJECT_NOT_EXIST;
        }
        return STATUS_OK;
    }

    @Override
    public PageObject<ProjectRefVO> queryProjectWithDistanceOfUser(String userId, String tenantid, Byte[] state, int start, int offset, String[] pkRoles, double longitude, double latitude) throws BusinessException {
        if (offset > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
            offset = CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE;
        }

        Map<String, ProjectRefVO> teamProMap = queryTeamProByUser(userId, tenantid, state, start, offset);
        Map<String, ProjectRefVO> orgProMap = queryOrgProByRoles(pkRoles, tenantid, state, start, offset);
        teamProMap.putAll(orgProMap);
        ProjectRefVO[] projectRefVOs = teamProMap.values().toArray(new ProjectRefVO[0]);
        if (ArrayUtils.isNotEmpty(projectRefVOs)) {
            //给组织名称以及编号赋值
            setProOrgInfo(tenantid, projectRefVOs);
            // 根据经纬度计算距离
            setProjectDistance(projectRefVOs, longitude, latitude);
            //排序
            sortProjectRef(projectRefVOs);
        }

        int count = projectRefVOs == null ? 0 : projectRefVOs.length;
        return new PageObject<>(projectRefVOs, count, start);
    }

    /**
     * 根据当前经纬度计算项目距离
     *
     * @param projectRefVOs
     * @param longitude
     * @param latitude
     */
    private void setProjectDistance(ProjectRefVO[] projectRefVOs, double longitude, double latitude) {
        if (longitude == -1 || latitude == -1)
            return;

        double distance;
        for (ProjectRefVO refVO : projectRefVOs) {
            if (refVO.getLongitude() != null && refVO.getLatitude() != null) {
                distance = DistanceUtils.getDistanceMeter(longitude, latitude, refVO.getLongitude().doubleValue(), refVO.getLatitude().doubleValue());
                refVO.setDistance(distance);
            }
        }
    }

    /**
     * 根据NC中的组织，查询组织
     */
    private Map<String, OrganizationVO> getOrg(String pkTenant, String[] pkSrcOrgs) throws BusinessException {
        Map<String, OrganizationVO> result = new HashMap<>();
        if (ArrayUtils.isEmpty(pkSrcOrgs)) return result;
        OrganizationVO[] organizationVOS = organizationQuery.queryByPkSrcs(pkTenant, pkSrcOrgs);
        if (ArrayUtils.isEmpty(organizationVOS)) return result;
        for (OrganizationVO vo : organizationVOS) {
            if (vo != null) {
                result.put(vo.getPkSrc(), vo);
            }
        }
        return result;
    }

    /**
     * 查询用户有权限的项目
     *
     * @param userId
     * @param tenantid
     * @param state
     * @param start
     * @param offset
     * @param pkRoles
     * @return
     * @throws BusinessException
     */
    private ProjectRefVO[] queryPermProByUser(String userId, String tenantid, Byte[] state, int start, int offset, String[] pkRoles) throws BusinessException {
        //Map对应key项目ID，value项目对象。teamProMap对应的是用户所在的团队对应的所有项目.
        Map<String, ProjectRefVO> teamProMap = queryTeamProByUser(userId, tenantid, state, start, offset);
        //Map对应key项目ID,value项目对象,orgProMap对应角色所对应的组织,组织下的所有项目.
        Map<String, ProjectRefVO> orgProMap = queryOrgProByRoles(pkRoles, tenantid, state, start, offset);
        //Map的key一致时就会覆盖,作用去重项目
        teamProMap.putAll(orgProMap);
        ProjectRefVO[] projectRefVOs = teamProMap.values().toArray(new ProjectRefVO[0]);

        if (ArrayUtils.isNotEmpty(projectRefVOs)) {
            //给组织名称以及编号赋值
            setProOrgInfo(tenantid, projectRefVOs);
            //排序
            sortProjectRef(projectRefVOs);
        }

        return projectRefVOs;
    }

    private void sortProjectRef(ProjectRefVO[] projectRefVOs) {

        if (ArrayUtils.isEmpty(projectRefVOs))
            return;

        Arrays.sort(projectRefVOs, new Comparator<ProjectRefVO>() {
            @Override
            public int compare(ProjectRefVO o1, ProjectRefVO o2) {
                if (o1 == o2) {
                    return 0;
                }
                if (o1 == null) {
                    return 1;
                }
                if (o2 == null) {
                    return -1;
                }
                // 先按距离项目位置的远近排序
                if (o1.getDistance() != null && o2.getDistance() != null) {
                    if (o1.getDistance() - o2.getDistance() > 0) {
                        return 1;
                    } else if (o1.getDistance() - o2.getDistance() < 0) {
                        return -1;
                    }
                } else if (o1.getDistance() != null && o2.getDistance() == null) {
                    return -1;
                } else if (o1.getDistance() == null && o2.getDistance() != null) {
                    return 1;
                }

                if (ChineseStringUtils.compareInDict(o1.getOrgCode(), o2.getOrgCode()) == 0) {
                    return ChineseStringUtils.compareInDict(o1.getScode(), o2.getScode());
                }
                return ChineseStringUtils.compareInDict(o1.getOrgCode(), o2.getOrgCode());
            }
        });
    }

    private void setProOrgInfo(String pkTenant, ProjectRefVO[] projectRefVOs) throws BusinessException {
        Set<String> pkOrgs = new HashSet<>();
        for (ProjectRefVO refVO : projectRefVOs) {
            if (refVO != null && StringUtils.isNotEmpty(refVO.getPkOrg())) pkOrgs.add(refVO.getPkOrg());
        }
        Map<String, OrganizationVO> recordOrg = getOrg(pkTenant, pkOrgs.toArray(new String[0]));
        for (ProjectRefVO refVO : projectRefVOs) {
            if (refVO != null && StringUtils.isNotEmpty(refVO.getPkOrg())) {
                OrganizationVO orgVO = recordOrg.get(refVO.getPkOrg());
                if (orgVO != null) {
                    refVO.setOrgName(orgVO.getSname());
                    refVO.setOrgCode(orgVO.getScode());
                }
            }
        }
    }

    private Map<String, ProjectRefVO> queryTeamProByUser(String userId, String tenantid, Byte[] state, int start, int offset) throws BusinessException {
        String[] pkProjects = queryPrjIdByUser(userId, tenantid, state, start, offset);

        if (ArrayUtils.isEmpty(pkProjects))
            return new HashMap<String, ProjectRefVO>();
        //返回的key为项目ID，value为项目对象
        return projectQuery.queryRefs(pkProjects);
    }

    /**
     * 根据用户查询项目团队的项目
     * @param userId
     * @param tenantid
     * @param state
     * @param start
     * @param offset
     * @return
     */
    private String[] queryPrjIdByUser(String userId, String tenantid, Byte[] state, int start, int offset) {
        //从pmbd_team_member表中查询该租户下，用户所在团队对应的项目。
        return mapper.queryProjectByUserAndStatus(userId, tenantid, state, start, offset);
    }

    /**
     * 根据角色查询项目id
     * @param pkRoles
     * @param tenantId
     * @param state
     * @return
     */
    private String[] queryPkProjectOrgProByRoles(String[] pkRoles, String tenantId, Byte[] state) {
        //用户角色为空
        if(pkRoles == null || pkRoles.length == 0) {
            return new String[0];
        }
        // 查询给角色分配的组织
        OrgAndRoleVO[] orgAndRoleVOs = roleMapper.getOrgByRole(tenantId, SqlUtil.getSqlIn(pkRoles));
        if (ArrayUtils.isEmpty(orgAndRoleVOs)){
            return new String[0];
        }
        List<String> pkSrcOrgs = Arrays.stream(orgAndRoleVOs).filter(vo -> vo != null && StringUtils.isNotEmpty(vo.getPkSrc())).map(OrgAndRoleVO::getPkSrc).collect(Collectors.toList());

        String[] projectIds = projectMapper.queryPrjIdByOrgsLimite(tenantId, isTenant(orgAndRoleVOs) ? null : pkSrcOrgs.toArray(new String[0]), state);

        return projectIds;
    }


    /**
     * 获取项目团队与角色的项目id
     * @param userId
     * @param tenantid
     * @param state
     * @param start
     * @param offset
     * @param pkRoles
     * @return
     */
    public List<String> getPermissionProjects(String userId, String tenantid, Byte[] state, int start, int offset, String[] pkRoles){
        if (offset > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
                 offset = CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE;
        }

        String[] teamPro = queryPrjIdByUser(userId, tenantid, state, start, offset);
        String[] rolePro = queryPkProjectOrgProByRoles(pkRoles, tenantid, state);
        if(rolePro == null && teamPro == null){
            return new ArrayList<String>();
        }else  if(teamPro == null && rolePro != null){
            return Arrays.asList(rolePro);
        }else   if(rolePro == null && teamPro != null){
            return Arrays.asList(teamPro);
        }
        List<String> rolePros = Arrays.asList(rolePro).stream().filter(vo -> vo !=null).collect(Collectors.toList());
        rolePros.addAll(Arrays.asList(teamPro).stream().filter(vo -> vo !=null).collect(Collectors.toList()));
        return rolePros.stream().distinct().collect(Collectors.toList());
    }
    /**
     *
     * @param orgAndRoleVOs
     * @return
     */
    private boolean isTenant(OrgAndRoleVO[] orgAndRoleVOs) {
        boolean isTenant = false;
        //判断该组织是不是最高组织租户,如果是则直接查租户下面的所有项目.如果不是则查该租户下面的该组织下面的所有项目.
        for (OrgAndRoleVO orgAndRoleVO : orgAndRoleVOs) {
            if ("Y".equals(orgAndRoleVO.getIsTenant())) {
                isTenant = true;
                break;
            }
        }
        return isTenant;
    }

    private Map<String, ProjectRefVO> queryOrgProByRoles(String[] pkRoles, String tenantId, Byte[] state, int start, int offset) {
        Map<String, ProjectRefVO> proRefMap = new HashMap<String, ProjectRefVO>();

        if (ArrayUtils.isEmpty(pkRoles))
            return proRefMap;

        // 查询给角色分配的组织
        OrgAndRoleVO[] orgAndRoleVOs = roleMapper.getOrgByRole(tenantId, SqlUtil.getSqlIn(pkRoles));

        if (ArrayUtils.isEmpty(orgAndRoleVOs))
            return proRefMap;



        ProjectRefVO[] projectRefVOs = null;

        if (isTenant(orgAndRoleVOs)) {
            projectRefVOs = projectMapper.queryPrjRefByOrgsLimite(tenantId, null, state, start, offset);
        } else {
            Set<String> pkSrcOrgSet = new HashSet<String>();
            for (OrgAndRoleVO vo : orgAndRoleVOs) {
                if (vo != null && StringUtils.isNotEmpty(vo.getPkSrc())) {
                    pkSrcOrgSet.add(vo.getPkSrc());
                }
            }
            projectRefVOs = projectMapper.queryPrjRefByOrgsLimite(tenantId, pkSrcOrgSet.toArray(new String[0]), state, start, offset);
        }

        if (ArrayUtils.isEmpty(projectRefVOs))
            return proRefMap;

        for (ProjectRefVO refVO : projectRefVOs) {
            proRefMap.put(refVO.getPkProject(), refVO);
        }

        return proRefMap;
    }

    private ProjectVO[] queryProByTeamAndOrg(String userId, String tenantid, Byte state, String[] filterOrgs) throws BusinessException {

        String[] pkProjects = mapper.queryProjectByUser(userId, tenantid, null, 0, CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE);

        if (ArrayUtils.isEmpty(pkProjects))
            return new ProjectVO[0];

        Set<String> pkProjectSet = new HashSet<>();
        pkProjectSet.addAll(Arrays.asList(pkProjects));

        List<ProjectVO> newProjectVOList = new ArrayList<>();

        ProjectVO[] joinProjects = projectMapper.queryVOByIds(BulkDataSplitUtils.getSplitDataSet(pkProjectSet));

        if(joinProjects == null || joinProjects.length <= 0){
            return new ProjectVO[0];
        }

        for(ProjectVO projectVO : joinProjects){
            if(state != null && projectVO.getProjectState() != state){
                continue;
            }

            if (ArrayUtils.isNotEmpty(filterOrgs)) {
                for (String filterOrg : filterOrgs) {
                    if (filterOrg.equals(projectVO.getPkOrg())){
                        newProjectVOList.add(projectVO);
                        break;
                    }
                }
            }else {
                newProjectVOList.add(projectVO);
            }
        }

        if(newProjectVOList.size() <= 0){
            return new ProjectVO[0];
        }

        joinProjects = newProjectVOList.toArray(new ProjectVO[]{});
        return joinProjects;
    }

    private ProjectVO[] queryProByOrg(String[] pkRoles, String tenantId, Byte state, int start, int offset, String[] pkOrgs) throws BusinessException {

        if (ArrayUtils.isEmpty(pkRoles))
            return new ProjectVO[0];

        if (ArrayUtils.isEmpty(pkOrgs)) {
            OrgAndRoleVO[] orgAndRoleVOs = roleMapper.getOrgByRole(tenantId, SqlUtil.getSqlIn(pkRoles));

            if (ArrayUtils.isEmpty(orgAndRoleVOs))
                return new ProjectVO[0];

            Set<String> pkOrgSet = new HashSet<>();

            for (OrgAndRoleVO orgAndRoleVO : orgAndRoleVOs) {
                if (StringUtils.isNotEmpty(orgAndRoleVO.getPkSrc())) {
                    pkOrgSet.add(orgAndRoleVO.getPkSrc());
                } else if (StringUtils.isEmpty(orgAndRoleVO.getPkOrganization())) {
                    // 角色关联了租户
                    pkOrgSet.add(tenantId);
                }
            }
            pkOrgs = pkOrgSet.toArray(new String[0]);
        }

        return projectMapper.queryPrjByOrgs(tenantId, pkOrgs.length > 0 ? pkOrgs : null, state);
    }

    /**
     * 查询当前用户有权限的施工中项目
     *
     * @param invocationContext 参数
     * @return 项目档案数据
     */
    @Override
    public Object queryOffLineData(OffLineInvocationContext invocationContext) throws BusinessException {
        String userId = invocationContext.getUserId();
        String tenantId = invocationContext.getTenantId();
        Map<String, Object> extendArgumentMap = invocationContext.getExtendArgumentMap();
        List<String> pkRoles = new ArrayList<>();
        if (extendArgumentMap != null) {
            Object arguments = extendArgumentMap.get(OffLineDataKeyConst.DATA_FROM_PROJECT);
            if (arguments != null) {
                pkRoles = (ArrayList<String>) arguments;
            }
        }

        // 查询有权限的施工中的项目
        PageObject<ProjectRefVO> pageObject = queryProjectWithDistanceOfUser(userId, tenantId, null, 0, 1000,
                pkRoles.toArray(new String[]{}), -1, -1);

        // 查询项目下的工序
        ProjectRefVO[] projectRefVOS = pageObject.getObjects();
        if (projectRefVOS == null || projectRefVOS.length <= 0) {
            return pageObject;
        }

        List<String> projectIds = new ArrayList<>();
        for (ProjectRefVO projectRefVO : projectRefVOS) {
            projectIds.add(projectRefVO.getPkProject());
        }

        Map<String, List<ProcedureRefVO>> procedureRefMap = procedureQuery.queryRefByProjectIds(projectIds.toArray(new String[]{}), tenantId);

        // 查询该该项目是否可以做综合验收
        Map<String, Map<Boolean, String>> acceptanceMap = acceptanceQuery.checkMakeBillByProjectIds(projectIds);

        //查询项目下的施工单位
        TeamEnterpriseRefVO[] teamEnterpriseRefVOS1 = teamEnterpriseQuery.queryConstructionUnitInProjects(projectIds.toArray(new String[]{}));
        List<TeamEnterpriseRefVO> teamEnterpriseRefVOSList1 = Arrays.asList(teamEnterpriseRefVOS1);
        Map<String, List<TeamEnterpriseRefVO>> teamEnterpriseRefMap1 = setProjectRefObject(teamEnterpriseRefVOSList1);

        //查询项目下的监理单位
        TeamEnterpriseRefVO[] teamEnterpriseRefVOS2 = teamEnterpriseQuery.querySupervisionUnitInProjects(projectIds.toArray(new String[]{}));
        List<TeamEnterpriseRefVO> teamEnterpriseRefVOSList2 = Arrays.asList(teamEnterpriseRefVOS2);
        Map<String, List<TeamEnterpriseRefVO>> teamEnterpriseRefMap2 = setProjectRefObject(teamEnterpriseRefVOSList2);

        //查询项目下的接受人/整改人/抄送人
        TeamMemberVO[] teamMemberVOS = teamMemberQuery.queryByprojects(projectIds.toArray(new String[]{}));
        List<TeamMemberVO> teamMemberVOSList = Arrays.asList(teamMemberVOS);
        Map<String, List<TeamMemberVO>> teamMemberVOSMap = setProjectRefObject(teamMemberVOSList);

        for (ProjectRefVO projectRefVO : projectRefVOS) {
            List<ProcedureRefVO> procedureRefVOList = procedureRefMap.get(projectRefVO.getPkProject());
            projectRefVO.setProcedureRefVOList(procedureRefVOList == null ? new ArrayList<ProcedureRefVO>() : procedureRefVOList);

            List<TeamEnterpriseRefVO> teamEnterpriseRefVOS = teamEnterpriseRefMap1.get(projectRefVO.getPkProject());
            projectRefVO.setConstructionUnit(teamEnterpriseRefVOS == null ? new ArrayList<TeamEnterpriseRefVO>() : teamEnterpriseRefVOS);

            List<TeamEnterpriseRefVO> teamEnterpriseRefVOList = teamEnterpriseRefMap2.get(projectRefVO.getPkProject());
            projectRefVO.setSupervisionUnit(teamEnterpriseRefVOList == null ? new ArrayList<TeamEnterpriseRefVO>() : teamEnterpriseRefVOList);

            List<TeamMemberVO> teamMemberVOList = teamMemberVOSMap.get(projectRefVO.getPkProject());
            projectRefVO.setTeamMemberVOS(teamMemberVOList == null ? new ArrayList<TeamMemberVO>() : teamMemberVOList);

            // 存放综合验收标识
            Map<Boolean, String> acceptanceCheckMap = acceptanceMap.get(projectRefVO.getPkProject());
            projectRefVO.setAcceptanceResultMap(acceptanceCheckMap);
        }

        return pageObject;
    }

    /**
     * 将所有的项目关联对象按projectId 进行归类
     *
     * @param objects 项目对象的关联对象集合
     * @param <T>
     * @return
     */
    public <T> Map<String, List<T>> setProjectRefObject(List<T> objects) {


        HashMap<String, List<T>> result = new HashMap<>();

        for (T object : objects) {
            try {
                Method getPkProject = object.getClass().getMethod("getPkProject", null);

                String pkProject = (String) getPkProject.invoke(object, null);

                List<T> ts = result.get(pkProject);

                if (ts == null) {
                    ArrayList<T> refObjects = new ArrayList<>();

                    refObjects.add(object);

                    result.put(pkProject, refObjects);
                } else {
                    ts.add(object);
                }
            } catch (Exception e) {

                e.printStackTrace();
            }
        }

        return result;
    }
}
